﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BeyondTVLibrary;
using System.Threading;
using System.IO;


namespace LiveTV
{
    public class Program
    {
        #region Shared Variables and Constants
        public static Boolean m_running = true;
        public static BeyondTVLibrary.BTVLicenseManager BTVLicense;
        public static BeyondTVLibrary.BTVLiveTVManager BTVLiveTV;
        public static BeyondTVLibrary.BTVScheduler BTVScheduler;
        public static BeyondTVLibrary.BTVLibrary BTVLibrary;
        public static readonly Guid NullSession = new Guid("00000000-0000-0000-0000-000000000000");
        public static LiveProviderStatus LiveStatus = new LiveProviderStatus();
        public static btvAuthentication AuthStruct = new btvAuthentication();
        #endregion
        #region Thread Variables
        public static System.Threading.ThreadStart RenewThread = new System.Threading.ThreadStart(Program.RenewLogon);
        public static Thread z_renewThread = new Thread(RenewThread);
        public static System.Threading.ThreadStart KeepAliveThread = new System.Threading.ThreadStart(Program.KeepAlive);
        public static Thread z_keepAlive = new Thread(KeepAliveThread);
        public static System.Threading.ThreadStart IPCRPC = new ThreadStart(CheckTVRPC);
        public static Thread IPC = new Thread(IPCRPC);
        #endregion
        #region Structs
        public struct btvAuthentication
        {
            public String username;
            public String password;
            public String Host;
            public int Port;
            public void Unserialize()
            {
                TextReader txtRead = new StreamReader(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\serviceLogon.rpc");
                Host = txtRead.ReadLine();
                Port = int.Parse(txtRead.ReadLine());
                try
                {
                    username = txtRead.ReadLine();
                }
                catch (Exception e)
                {
#if(DEBUG)
                    Console.WriteLine("Username not specified, blanking.");
#endif
                    username = "";
                }
                try
                {
                    password = txtRead.ReadLine();
                }
                catch (Exception e)
                {
#if(DEBUG)
                    Console.WriteLine("Password not specified, blanking.");
#endif
                    password = "";
                }

#if(DEBUG)
                Console.WriteLine("[DEBUG-AUTHSTRUCT] Host: " + Host + ":" + Port);
                Console.WriteLine("[DEBUG-AUTHSTRUCT] User/Pass: " + username + ":" + password);
#endif
            }
        }

        public struct LiveProviderStatus
        {
            public Boolean isSessionRunning;
            public String AuthTicket;
            public Guid SessionID;
            public String Serialize()
            {
                if (isSessionRunning == false)
                {
                    LiveStatus.SessionID = new Guid("00000000-0000-0000-0000-000000000000");
                }
                return (isSessionRunning + "#" + AuthTicket + "#" + SessionID);
            }
        }
        #endregion
        #region Threads
        static void KeepAlive()
        {
            while (true)
            {
                if (LiveStatus.isSessionRunning == true)
                {
#if(DEBUG)
                Console.WriteLine("[DEBUG-KeepAliveThread] Ready to send KA request.");
#endif
                    try
                    {
                        BTVLiveTV.KeepAlive(LiveStatus.AuthTicket, LiveStatus.SessionID);
                    }
                    catch (Exception e)
                    {
#if(DEBUG)
                    Console.WriteLine("[DEBUG-KeepAliveThread] Exception: " + e.Message);
#endif
                    }
#if(DEBUG)
                Console.WriteLine("[DEBUG-KeepAliveThread] putting thread to sleep.");
#endif

                    Thread.Sleep(15000);
                }
            }
        }
        static public void RenewLogon()
        {
            while (true)
            {
#if(DEBUG)
                Console.WriteLine("[DEBUG-RenewLogonThread] Renewing Logon Request..");
#endif
                BTVLicense.RenewLogonSession(LiveStatus.AuthTicket);
                Thread.Sleep(5000);
            }
        }
        static public void CheckTVRPC()
        {
            Boolean CommandsProcessed = false;
            String Commands;
            if (File.Exists(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\LiveTVProvider.rpc.in"))
            {
#if(DEBUG)
                Console.WriteLine("[DEBUG] RPC file exists, Reading command.");
#endif
                try
                {

                    TextReader txtRead = new StreamReader(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\LiveTVProvider.rpc.in");
                    Commands = txtRead.ReadLine();
                    txtRead.Close();
                    Console.WriteLine("[DEBUG] Read File. Deleting");
                    File.Delete(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\LiveTVProvider.rpc.in");
                    CommandsProcessed = true;
                    Console.WriteLine("[DEBUG] Command: " + Commands);
                }
                catch (Exception e)
                {
                    Console.WriteLine("[DEBUG] " + e.Message);
                    return;
                }
            }
            else
            {
                Commands = null;
            }

            switch (Commands)
            {
                case "shutdown":
                    ShutdownLiveTVProvider();
                    break;
                case "endSession":
                    EndCurrentSession();
                    break;
                case "beginSession":
                    BeginNewSession();
                    break;
                case "startup":
                    Console.WriteLine("[DEBUG] got client startup request, replying with ready status.");
                    TextWriter readystate = new StreamWriter(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\LiveTVProvider.rpc.out");
                    readystate.WriteLine("LiveProviderReady\r\n"); //This is a dummy file to tell the XBMC script that it's time to start playing.
                    readystate.Close();
                    break;
                /*case "getStatus":
#if(DEBUG)
                    Console.WriteLine("[DEBUG] Writing Out-RPC");
#endif
                    TextWriter txtWrite = new StreamWriter("C:\\Windows\\TVRPC\\LiveTVProvider.rpc.out");
                    txtWrite.WriteLine(LiveStatus.Serialize()+"\r\n");
                    txtWrite.Close();
                    break;*/
            }

        }
        #endregion
        #region Program
        static void Main(string[] args)
        {
#if(!DEBUG)
            
#endif
            PVSPropertyBag LogonBag;
            if (File.Exists(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase+"\\serviceLogon.rpc"))
            {
                AuthStruct.Unserialize();
#if(DEBUG)
                Console.WriteLine("[DEBUG-AUTH] Host: " + AuthStruct.Host);
                Console.WriteLine("[DEBUG-AUTH] Port: " + AuthStruct.Port);
                Console.WriteLine("[DEBUG-AUTH] Username: " + AuthStruct.username);
                Console.WriteLine("[DEBUG-AUTH] Password: " + AuthStruct.password);
#endif
                BTVLicense = new BTVLicenseManager(AuthStruct.Host,AuthStruct.Port);
                BTVLibrary = new BTVLibrary(AuthStruct.Host,AuthStruct.Port);
                BTVLiveTV = new BTVLiveTVManager(AuthStruct.Host, AuthStruct.Port);
                BTVScheduler = new BTVScheduler(AuthStruct.Host, AuthStruct.Port);
                LogonBag = BTVLicense.LogonRemote("", AuthStruct.username, AuthStruct.password);
            }
            else
            {
                BTVLicense = new BTVLicenseManager("10.0.0.1", 8129);
                BTVLibrary = new BTVLibrary("10.0.0.1", 8129);
                BTVLiveTV = new BTVLiveTVManager("10.0.0.1", 8129);
                BTVScheduler = new BeyondTVLibrary.BTVScheduler("10.0.0.1", 8129)
                LogonBag = BTVLicense.LogonRemote("", "","");
            }
            
            String AuthTicket = LogonBag.Properties[0].Value;
            z_renewThread.Start();
            z_keepAlive.Start();
            LiveStatus.AuthTicket = AuthTicket;
            LiveStatus.isSessionRunning = false;
            
            while (m_running == true)
            {
                //Lovely Loop for which the system keeps the program running.
            }
#if(DEBUG)
            Console.WriteLine("[DEBUG] Shutting down provider..");
#endif
        }

        static public void ShutdownLiveTVProvider()
        {
#if(DEBUG)
            Console.WriteLine("[DEBUG] Got RPC Shutdown.");
#endif
            z_renewThread.Abort();
            z_keepAlive.Abort();
            if (LiveStatus.isSessionRunning == true)
            {
                BTVLiveTV.EndSession(LiveStatus.AuthTicket, LiveStatus.SessionID);
            }
            TextWriter txtWriter = new StreamWriter(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\LiveTVProvider.rpc.out");
            txtWriter.WriteLine("shutdown\r\n");
            txtWriter.Close();
            File.Delete(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\LiveTVProvider.rpc.out");
            File.Delete(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\LiveTVProvider.rpc.in");
            m_running = false;
        }
        #endregion
        #region This is to be moved to new assembly.
      /*static public string AddRecording()
        {
            BTVScheduler.AddRecordingJob(LiveStatus.AuthTicket, ,0); # This isn't available right now.
        }*/ 
        static public string GetChannel()
        {
            return BTVLiveTV.GetChannel(LiveStatus.AuthTicket, LiveStatus.SessionID);
        }
        static public bool SetChannel(string Channel) 
        {
            if(LiveStatus.isSessionRunning == false) 
            {
                return false;
            }
            BTVLiveTV.SetChannel(LiveStatus.AuthTicket, LiveStatus.SessionID, Channel);
            if (BTVLiveTV.GetChannel(LiveStatus.AuthTicket, LiveStatus.SessionID) == Channel)
            {
                return true;
            }
        }
        static public void BeginNewSession()
        {
            LiveStatus.SessionID = BTVLiveTV.NewWebSession(LiveStatus.AuthTicket);
            if (NullSession == LiveStatus.SessionID)
            {
                LiveStatus.isSessionRunning = false;
            }
            else
            {
                LiveStatus.isSessionRunning = true;
                Console.WriteLine("[DEBUG] got session, telling client to connect.");
                TextWriter txtWriter = new StreamWriter(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\LiveTVProvider.rpc.out");
                txtWriter.WriteLine("connect\r\n");
                txtWriter.Close();
            }
        }
        static public void EndCurrentSession()
        {
#if(DEBUG)
            Console.WriteLine("[DEBUG] Ending Current Session: Reason: Got endSession RPC command.");
#endif
            try
            {
                BTVLiveTV.EndSession(LiveStatus.AuthTicket, LiveStatus.SessionID);
                z_keepAlive.Abort();
            }
            catch (Exception e)
            {
#if(DEBUG)
                Console.WriteLine("[DEBUG] Unable to end current Session, Maybe already ended (Bad Keep Alive thread.)");
#endif
            }

            LiveStatus.SessionID = new Guid("00000000-0000-0000-0000-000000000000");
            LiveStatus.isSessionRunning = false;
        }
        #endregion
    }
}
